home *** CD-ROM | disk | FTP | other *** search
- ;;; CMPLAM Lambda expression.
- ;;;
- ;; Copyright (C) 1994 M. Hagiya, W. Schelter, T. Yuasa
-
- ;; This file is part of GNU Common Lisp, herein referred to as GCL
- ;;
- ;; GCL is free software; you can redistribute it and/or modify it under
- ;; the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE as published by
- ;; the Free Software Foundation; either version 2, or (at your option)
- ;; any later version.
- ;;
- ;; GCL is distributed in the hope that it will be useful, but WITHOUT
- ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- ;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
- ;; License for more details.
- ;;
- ;; You should have received a copy of the GNU Library General Public License
- ;; along with GCL; see the file COPYING. If not, write to the Free Software
- ;; Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-
- (in-package 'compiler)
-
- ;;; During Pass1, a lambda-list
- ;;;
- ;;; ( { var }*
- ;;; [ &optional { var | ( var [ initform [ svar ] ] ) }* ]
- ;;; [ &rest var ]
- ;;; [ &key { var | ( { var | ( kwd var ) } [initform [ svar ]])}*
- ;;; [&allow-other-keys]]
- ;;; [ &aux {var | (var [initform])}*]
- ;;; )
- ;;;
- ;;; is transformed into
- ;;;
- ;;; ( ( { var }* ) ; required
- ;;; ( { (var initform svar) }* ) ; optional
- ;;; { var | nil } ; rest
- ;;; key-flag
- ;;; ( { ( kwd-vv-index var initform svar) }* ) ; key
- ;;; allow-other-keys-flag
- ;;; )
- ;;;
- ;;; where
- ;;; svar: nil ; means svar is not supplied
- ;;; | var
- ;;;
- ;;; &aux parameters will be embedded into LET*.
- ;;;
- ;;; c1lambda-expr receives
- ;;; ( lambda-list { doc | decl }* . body )
- ;;; and returns
- ;;; ( lambda info-object lambda-list' doc body' )
- ;;;
- ;;; Doc is NIL if no doc string is supplied.
- ;;; Body' is body possibly surrounded by a LET* (if &aux parameters are
- ;;; supplied) and an implicit block.
-
- (defmacro ck-spec (condition)
- `(unless ,condition
- (cmperr "The parameter specification ~s is illegal." spec)))
-
- (defmacro ck-vl (condition)
- `(unless ,condition
- (cmperr "The lambda list ~s is illegal." vl)))
-
-
- ;;;the following code implements downward closures.
- ;;;These are like closures, except they are guaranteed not
- ;;;to survive past the exit of the function in which they
- ;;;are born.
-
-
- (defmacro downward-function (x)
- `(function ,x))
-
- (setf (get 'downward-function 'c1special)
- 'c1downward-function)
-
- (defun c1downward-function (x)
- (let* ((tem (c1expr (list 'function (car x))))
- (info (cadr tem)))
- ;; for the moment we only allow downward closures with no args
- (cond ((and (consp x) (consp (car x))
- (eq (caar x) 'lambda)
- (null (second (car x))))
- (dolist (var (info-referred-vars info))
- (cond ((and (eq (var-kind var) 'lexical)
- (var-ref-ccb var) t)
- (setf (var-kind var) 'down)))
- )
- (setf (car tem) 'downward-function)
- tem)
- (t tem))))
-
- (si::putprop 'downward-function 'c2downward-function 'c2)
- (si:putprop 'make-dclosure 'wt-make-dclosure 'wt-loc)
-
- (defun wt-make-dclosure (cfun clink)clink ;;Dbase=base0
- (wt-nl "(DownClose"cfun".t=t_dclosure,DownClose" cfun ".dc_self=LC" cfun","
- "DownClose" cfun ".dc_env=base0,(object)&DownClose" cfun ")"))
-
- (defun wfs-error ()
- (error "This error is not supposed to occur: Contact Schelter ~
- ~%wfs@math.utexas.edu"))
-
- (defun wt-downward-closure-macro (cfun)
- (cond (*downward-closures*
- (wt-h "#define DCnames" cfun " ")
- (setq *downward-closures* (delete 'dcnames *downward-closures*))
- (cond (*downward-closures*
- (wt-h1 "struct dclosure ")
- (do ((v *downward-closures* (cdr v)))
- ((null v))
- (wt-h1 "DownClose")
- (wt-h1 (car v))
- (if (cdr v) (wt-h1 ",")))
- (wt-h1 ";"))))))
-
- (defun c2downward-function (funob)
- (let ((fun (make-fun :name 'closure :cfun (next-cfun))))
- (push (list 'dclosure (if (null *clink*) nil (cons 0 0))
- *ccb-vs* fun funob)
- *local-funs*)
- (push fun *closures*)
- (push (fun-cfun fun) *downward-closures*)
- (unwind-exit (list 'make-dclosure (fun-cfun fun) *clink*))))
-
-
-
- (defun c1lambda-expr (lambda-expr
- &optional (block-name nil block-it)
- &aux (requireds nil) (optionals nil) (rest nil)
- (keywords nil) (key-flag nil)
- lambda-list
- (allow-other-keys nil) (aux-vars nil)
- (aux-inits nil) doc vl spec body ss is ts
- other-decls vnames
- (*vars* *vars*)
- (info (make-info))
- (aux-info nil)
- (setjmps *setjmps*)
- )
- (cmpck (endp lambda-expr)
- "The lambda expression ~s is illegal." (cons 'lambda lambda-expr))
-
- (multiple-value-setq (body ss ts is other-decls doc)
- (c1body (cdr lambda-expr) t))
-
- (when block-it (setq body (list (cons 'block (cons block-name body)))))
-
- (c1add-globals ss)
-
- (setq vl (car lambda-expr))
- (block parse
- (tagbody
- Lreq
- (when (null vl) (return-from parse))
- (ck-vl (consp vl))
- (case (setq spec (pop vl))
- (&optional (go Lopt))
- (&rest (go Lrest))
- (&key (go Lkey))
- (&aux (go Laux)))
- (let ((v (c1make-var spec ss is ts)))
- (push spec vnames)
- (push v *vars*)
- (push v requireds))
- (go Lreq)
-
- Lopt
- (when (null vl) (return-from parse))
- (ck-vl (consp vl))
- (case (setq spec (pop vl))
- (&rest (go Lrest))
- (&key (go Lkey))
- (&aux (go Laux)))
- (cond ((not (consp spec))
- (let ((v (c1make-var spec ss is ts)))
- (push spec vnames)
- (push (list v (default-init (var-type v)) nil) optionals)
- (push v *vars*)))
- ((not (consp (cdr spec)))
- (ck-spec (null (cdr spec)))
- (let ((v (c1make-var (car spec) ss is ts)))
- (push (car spec) vnames)
- (push (list v (default-init (var-type v)) nil) optionals)
- (push v *vars*)))
- ((not (consp (cddr spec)))
- (ck-spec (null (cddr spec)))
- (let ((init (c1expr* (cadr spec) info))
- (v (c1make-var (car spec) ss is ts)))
- (push (car spec) vnames)
- (push
- (list v (and-form-type (var-type v) init (cadr spec)) nil)
- optionals)
- (push v *vars*)))
- (t
- (ck-spec (null (cdddr spec)))
- (let ((init (c1expr* (cadr spec) info))
- (v (c1make-var (car spec) ss is ts))
- (sv (c1make-var (caddr spec) ss is ts))
- )
- (push (car spec) vnames)
- (push (caddr spec) vnames)
- (push
- (list v (and-form-type (var-type v) init (cadr spec)) sv)
- optionals)
- (push v *vars*)
- (push sv *vars*))))
- (go Lopt)
-
- Lrest
- (ck-vl (consp vl))
- (push (car vl) vnames)
- (setq rest (c1make-var (pop vl) ss is ts))
- (push rest *vars*)
- (when (null vl) (return-from parse))
- (ck-vl (consp vl))
- (case (setq spec (pop vl))
- (&key (go Lkey))
- (&aux (go Laux)))
- (cmperr "Either &key or &aux is missing before ~s." spec)
-
- Lkey
- (setq key-flag t)
- (when (null vl) (return-from parse))
- (ck-vl (consp vl))
- (case (setq spec (pop vl))
- (&aux (go Laux))
- (&allow-other-keys (setq allow-other-keys t)
- (when (null vl) (return-from parse))
- (ck-vl (consp vl))
- (case (setq spec (pop vl))
- (&aux (go Laux)))
- (cmperr "&aux is missing before ~s." spec)))
- (when (not (consp spec)) (setq spec (list spec)))
- (cond ((consp (car spec))
- (ck-spec (and (keywordp (caar spec))
- (consp (cdar spec))
- (null (cddar spec))))
- (setq spec (cons (caar spec) (cons (cadar spec) (cdr spec)))))
- (t
- (ck-spec (symbolp (car spec)))
- (setq spec (cons (intern (string (car spec)) 'keyword)
- (cons (car spec) (cdr spec))))))
- (cond ((not (consp (cddr spec)))
- (ck-spec (null (cddr spec)))
- (let ((v (c1make-var (cadr spec) ss is ts)))
- (push (cadr spec) vnames)
- (push
- (list (car spec) v (default-init (var-type v))
- (make-var :kind 'DUMMY))
- keywords)
- (push v *vars*)))
- ((not (consp (cdddr spec)))
- (ck-spec (null (cdddr spec)))
- (let ((init (c1expr* (caddr spec) info))
- (v (c1make-var (cadr spec) ss is ts)))
- (push (cadr spec) vnames)
- (push (list (car spec) v
- (and-form-type (var-type v) init (caddr spec))
- (make-var :kind 'DUMMY))
- keywords)
- (push v *vars*)))
- (t
- (ck-spec (null (cddddr spec)))
- (let ((init (c1expr* (caddr spec) info))
- (v (c1make-var (cadr spec) ss is ts))
- (sv (c1make-var (cadddr spec) ss is ts)))
- (push (cadr spec) vnames)
- (push (cadddr spec) vnames)
- (push (list (car spec) v
- (and-form-type (var-type v) init (caddr spec))
- sv)
- keywords)
- (push v *vars*)
- (push sv *vars*))))
- (go Lkey)
-
- Laux
- (setq aux-info (make-info))
- Laux1
- (when (null vl) (add-info info aux-info) (return-from parse))
- (ck-vl (consp vl))
- (setq spec (pop vl))
- (cond ((consp spec)
- (cond ((not (consp (cdr spec)))
- (ck-spec (null (cdr spec)))
- (let ((v (c1make-var (car spec) ss is ts)))
- (push (car spec) vnames)
- (push (default-init (var-type v)) aux-inits)
- (push v aux-vars)
- (push v *vars*)))
- (t
- (ck-spec (null (cddr spec)))
- (let ((init (c1expr* (cadr spec) aux-info))
- (v (c1make-var (car spec) ss is ts)))
- (push (car spec) vnames)
- (push (and-form-type (var-type v) init (cadr spec))
- aux-inits)
- (push v aux-vars)
- (push v *vars*)))))
- (t
- (let ((v (c1make-var spec ss is ts)))
- (push spec vnames)
- (push (default-init (var-type v)) aux-inits)
- (push v aux-vars)
- (push v *vars*))))
- (go Laux1)
- )
- )
- (setq requireds (reverse requireds)
- optionals (reverse optionals)
- keywords (reverse keywords)
- aux-vars (reverse aux-vars)
- aux-inits (reverse aux-inits))
-
- (check-vdecl vnames ts is)
-
- (setq body (c1decl-body other-decls body))
-
- (add-info info (cadr body))
-
- (dolist** (var requireds) (check-vref var))
- (dolist** (opt optionals)
- (check-vref (car opt))
- (when (caddr opt) (check-vref (caddr opt))))
- (when rest (check-vref rest))
- (dolist** (kwd keywords)
- (check-vref (cadr kwd))
- (when (cadddr kwd) (check-vref (cadddr kwd))))
- (dolist** (var aux-vars) (check-vref var))
-
- (when aux-vars
- (add-info aux-info (cadr body))
- (setq body (list 'let* aux-info aux-vars aux-inits body))
- (or (eql setjmps *setjmps*) (setf (info-volatile aux-info) t)))
-
- (setq body (fix-down-args requireds body block-name))
- (setq lambda-list
- (list requireds optionals rest key-flag keywords allow-other-keys))
- (and *record-call-info* (record-arg-info lambda-list))
- (list 'lambda
- info
- lambda-list
- doc
- body)
- )
-
-
- ;;this makes a let for REQUIREDS which are used in a downward
- ;;lexical closure
-
- (defun fix-down-args(requireds body name &aux auxv auxinit info v)
- (let ((types (get name 'proclaimed-arg-types))
- (fixed (get name 'fixed-args)))
- (do ((vv requireds (cdr vv))
- (typ types (cdr typ)))
- ((null vv))
- (setq v (car vv))
- (cond ((not (or fixed (eq (car typ) t)))
- (return-from fix-down-args body))
- ((and (eq (var-kind v) 'DOWN) (eq (var-loc v) 'object))
- ;;a downward variable could not have been special
- ;;and must be type t. We create a new variable
- ;;for the arg, and bind the old one to it.
- (let* ((new (c1make-var (var-name v) nil nil nil))
- (init
- (list 'var
- (or info (setq info (make-info)))
- (list new nil))))
- (push v auxv)
- (setf (car vv) new)
- (push new (info-referred-vars info))
- (push init auxinit)))))
- (if auxv (list 'let* info auxv auxinit body)
- body)))
-
- (defun the-parameter (name)
- (cmpck (not (symbolp name)) "The parameter ~s is not a symbol." name)
- (cmpck (constantp name) "The constant ~s is being bound." name)
- name
- )
-
- (defvar *rest-on-stack* nil) ;; non nil means put rest arg on C stack.
-
- (defun c2lambda-expr (lambda-list body &optional (fname nil s-fname))
- (let ((*tail-recursion-info* ;;; Tail recursion possible if
- (if (and *do-tail-recursion*
- s-fname ;;; named function,
- (dolist* (var (car lambda-list) t)
- (when (var-ref-ccb var) (return nil)))
- ;;; no required is closed in a closure,
- (null (cadr lambda-list)) ;;; no optionals,
- (null (caddr lambda-list)) ;;; no rest parameter, and
- (not (cadddr lambda-list))) ;;; no keywords.
- (cons fname (car lambda-list))
- nil)))
- (let ((*rest-on-stack*
- (cond ((and (caddr lambda-list)
- (eq (var-type (caddr lambda-list)) :dynamic-extent))
- t)
- (t *rest-on-stack*))))
- (if (cadddr lambda-list) ;;; key-flag
- (c2lambda-expr-with-key lambda-list body)
- (c2lambda-expr-without-key lambda-list body)))
- ))
-
- (defun c2lambda-expr-without-key
- (lambda-list body
- &aux (requireds (car lambda-list))
- (optionals (cadr lambda-list))
- (rest (caddr lambda-list))
- (labels nil)
- (*unwind-exit* *unwind-exit*)
- (*vs* *vs*) (*clink* *clink*) (*ccb-vs* *ccb-vs*)
- (block-p nil)
- )
- (declare (object requireds optionals rest))
- ;;; Allocate immediate-type parameters.
-
- (flet ((do-decl (var)
- (let ((kind (c2var-kind var)))
- (declare (object kind))
- (when kind
- (let ((cvar (next-cvar)))
- (setf (var-kind var) kind)
- (setf (var-loc var) cvar)
- (wt-nl)
- (unless block-p (wt "{") (setq block-p t))
- (wt-var-decl var)
- )))))
-
- (dolist** (v requireds) (do-decl v))
- (dolist** (opt optionals)
- (do-decl (car opt))
- (when (caddr opt) (do-decl (caddr opt))))
- (when rest (do-decl rest))
- )
- ;;; check arguments
- (when (or *safe-compile* *compiler-check-args*)
- (cond ((or rest optionals)
- (when requireds
- (wt-nl "if(vs_top-vs_base<" (length requireds)
- ") too_few_arguments();"))
- (unless rest
- (wt-nl "if(vs_top-vs_base>"
- (+ (length requireds) (length optionals))
- ") too_many_arguments();")))
- (t (wt-nl "check_arg(" (length requireds) ");"))))
-
- ;;; Allocate the parameters.
- (dolist** (var requireds) (setf (var-ref var) (vs-push)))
- (dolist** (opt optionals) (setf (var-ref (car opt)) (vs-push)))
- (when rest (setf (var-ref rest) (vs-push)))
- (dolist** (opt optionals)
- (when (caddr opt) (setf (var-ref (caddr opt)) (vs-push))))
-
- ;;; Bind required parameters.
- (dolist** (var requireds) (c2bind var))
-
- ;;; Bind optional parameters as long as there remain arguments.
- ;;; The compile-time binding is discarded because they are bound again.
- (when (and (or optionals rest) (not (null requireds)))
- (wt-nl "vs_base=vs_base+" (length requireds) ";"))
- (cond (optionals
- (let ((*clink* *clink*)
- (*unwind-exit* *unwind-exit*)
- (*ccb-vs* *ccb-vs*))
- (when rest
- (wt-nl "vs_top[0]=Cnil;")
- (wt-nl "{object *p=vs_top, *q=vs_base+" (length optionals) ";")
- (wt-nl " for(;p>q;p--)p[-1]=MMcons(p[-1],p[0]);}"))
- (do ((opts optionals (cdr opts)))
- ((endp opts))
- (declare (object opts))
- (push (next-label) labels)
- (wt-nl "if(vs_base>=vs_top){")
- (reset-top)
- (wt-go (car labels)) (wt "}")
- (c2bind (caar opts))
- (when (caddar opts) (c2bind-loc (caddar opts) t))
- (when (cdr opts) (wt-nl "vs_base++;"))
- )
- (when rest (c2bind rest))
- )
-
- (wt-nl) (reset-top)
-
- (let ((label (next-label)))
- (wt-nl) (wt-go label)
-
- (setq labels (reverse labels))
-
- ;;; Bind unspecified optional parameters.
- (dolist** (opt optionals)
- (wt-label (car labels))
- (pop labels)
- (c2bind-init (car opt) (cadr opt))
- (when (caddr opt) (c2bind-loc (caddr opt) nil)))
-
- (when rest (c2bind-loc rest nil))
-
- (wt-label label)))
- (rest
- (wt-nl "vs_top[0]=Cnil;")
- (wt-nl "{object *p=vs_top;")
- (wt-nl " for(;p>vs_base;p--)p[-1]="
- (if *rest-on-stack* "ON_STACK_CONS" "MMcons")
- "(p[-1],p[0]);}")
- (c2bind rest)
- (wt-nl)
- (reset-top))
- (t
- (wt-nl)
- (reset-top)))
-
- (when *tail-recursion-info*
- (push 'tail-recursion-mark *unwind-exit*) (wt-nl1 "TTL:;"))
-
- ;;; Now the parameters are ready!
- (c2expr body)
-
- (when block-p (wt-nl "}"))
- )
-
- (defun c2lambda-expr-with-key
- (lambda-list body
- &aux (requireds (nth 0 lambda-list))
- (optionals (nth 1 lambda-list))
- (rest (nth 2 lambda-list))
- (keywords (nth 4 lambda-list))
- (allow-other-keys (nth 5 lambda-list))
- (labels nil)
- (*unwind-exit* *unwind-exit*)
- (*vs* *vs*) (*clink* *clink*) (*ccb-vs* *ccb-vs*)
- (block-p nil)
- )
- (declare
- (object requireds optionals rest keywords allow-other-keys))
- ;;; Allocate immediate-type parameters.
- (flet ((do-decl (var)
- (let ((kind (c2var-kind var)))
- (declare (object kind))
- (when kind
- (let ((cvar (next-cvar)))
- (setf (var-kind var) kind)
- (setf (var-loc var) cvar)
- (wt-nl)
- (unless block-p (wt "{") (setq block-p t))
- (wt-var-decl var)
- )))))
-
- (dolist** (v requireds) (do-decl v))
- (dolist** (opt optionals)
- (do-decl (car opt))
- (when (caddr opt) (do-decl (caddr opt))))
- (when rest (do-decl rest))
- (dolist** (kwd keywords)
- (do-decl (cadr kwd))
- (when (cadddr kwd) (do-decl (cadddr kwd))))
- )
- ;;; Check arguments.
- (when (and (or *safe-compile* *compiler-check-args*) requireds)
- (when requireds
- (wt-nl "if(vs_top-vs_base<" (length requireds)
- ") too_few_arguments();")))
-
- ;;; Allocate the parameters.
- (dolist** (var requireds) (setf (var-ref var) (vs-push)))
- (dolist** (opt optionals)
- (setf (var-ref (car opt)) (vs-push)))
- (when rest (setf (var-ref rest) (vs-push)))
- (dolist** (kwd keywords)
- (setf (var-ref (cadr kwd)) (vs-push)))
- (dolist** (kwd keywords)
- (setf (var-ref (cadddr kwd)) (vs-push)))
- (dolist** (opt optionals)
- (when (caddr opt) (setf (var-ref (caddr opt)) (vs-push))))
-
- ;;; Assign rest and keyword parameters first.
- ;;; parse_key does not change vs_base and vs_top.
-
- (wt-nl "parse_key(vs_base")
- (when (or requireds optionals)
- (wt "+" (+ (length requireds) (length optionals))))
- (if rest (wt ",TRUE,") (wt ",FALSE,"))
- (if allow-other-keys (wt "TRUE,") (wt "FALSE,"))
- (wt (length keywords))
- (dolist** (kwd keywords) (wt ",VV[" (add-symbol (car kwd)) "]"))
- (wt ");")
-
- ;;; Bind required parameters.
- (dolist** (var requireds) (c2bind var))
-
- ;;; Bind optional parameters as long as there remain arguments.
- ;;; The compile-time binding is discarded because they are bound again.
-
- (when optionals
-
- (when requireds (wt-nl "vs_base += " (length requireds) ";"))
-
- (let ((*clink* *clink*)
- (*unwind-exit* *unwind-exit*)
- (*ccb-vs* *ccb-vs*))
- (do ((opts optionals (cdr opts)))
- ((endp opts))
- (declare (object opts))
- (push (next-label) labels)
- (wt-nl "if(vs_base>=vs_top){vs_top=sup;")
- (wt-go (car labels)) (wt "}")
- (c2bind (caar opts))
- (when (caddar opts) (c2bind-loc (caddar opts) t))
- (when (cdr opts) (wt-nl "vs_base++;"))))
-
- (setq labels (reverse labels))
- )
-
- (wt-nl "vs_top=sup;")
-
- (when optionals
- (let ((label (next-label)))
- (wt-go label)
-
- ;;; Bind unspecified optional parameters.
-
- (dolist** (opt optionals)
- (wt-label (car labels))
- (pop labels)
- (c2bind-init (car opt) (cadr opt))
- (when (caddr opt) (c2bind-loc (caddr opt) nil)))
-
- (wt-label label)
- ))
-
- (when rest (c2bind rest))
-
- ;;; Bind keywords.
-
- (dolist** (kwd keywords)
- (cond ((and (eq (caaddr kwd) 'LOCATION) (null (caddr (caddr kwd))))
- ;;; Cnil has been set if keyword parameter is not supplied.
- (c2bind (cadr kwd)))
- (t
- (wt-nl "if(") (wt-vs (var-ref (cadddr kwd))) (wt "==Cnil){")
- (let ((*clink* *clink*)
- (*unwind-exit* *unwind-exit*)
- (*ccb-vs* *ccb-vs*))
- (c2bind-init (cadr kwd) (caddr kwd)))
- (wt-nl "}else{")
- (c2bind (cadr kwd))
- (wt "}")))
- (unless (eq (var-kind (cadddr kwd)) 'DUMMY) (c2bind (cadddr kwd))))
-
- ;;; Now the parameters are ready, after all!
- (c2expr body)
-
- (when block-p (wt-nl "}"))
- )
-
- (defun need-to-set-vs-pointers (lambda-list)
- ;;; On entry to in-line lambda expression,
- ;;; vs_base and vs_top must be set iff,
- (or *safe-compile*
- *compiler-check-args*
- (nth 1 lambda-list) ;;; optional,
- (nth 2 lambda-list) ;;; rest, or
- (nth 3 lambda-list) ;;; key-flag.
- ))
-
-
- ;;; The DEFMACRO compiler.
-
- ;;; valid lambda-list to DEFMACRO is:
- ;;;
- ;;; ( [ &whole sym ]
- ;;; [ &environment sym ]
- ;;; { v }*
- ;;; [ &optional { sym | ( v [ init [ v ] ] ) }* ]
- ;;; { [ { &rest | &body } v ]
- ;;; [ &key { sym | ( { sym | ( key v ) } [ init [ v ]] ) }*
- ;;; [ &allow-other-keys ]]
- ;;; [ &aux { sym | ( v [ init ] ) }* ]
- ;;; | . sym }
- ;;; )
- ;;;
- ;;; where v is short for { defmacro-lambda-list | sym }.
- ;;; Defamcro-lambda-list is defined as:
- ;;;
- ;;; ( { v }*
- ;;; [ &optional { sym | ( v [ init [ v ] ] ) }* ]
- ;;; { [ { &rest | &body } v ]
- ;;; [ &key { sym | ( { sym | ( key v ) } [ init [ v ]] ) }*
- ;;; [ &allow-other-keys ]]
- ;;; [ &aux { sym | ( v [ init ] ) }* ]
- ;;; | . sym }
- ;;; )
-
- (defvar *vnames*)
- (defvar *dm-info*)
- (defvar *dm-vars*)
-
-
- (defun c1dm (macro-name vl body
- &aux (*vs* *vs*) (whole nil) (env nil)
- (setjmps *setjmps*)
- (*vnames* nil) (*dm-info* (make-info)) (*dm-vars* nil)
- doc ss is ts other-decls ppn)
-
- (multiple-value-setq (body ss ts is other-decls doc) (c1body body t))
- (setq body (list (list* 'block macro-name body)))
-
- (c1add-globals ss)
-
- (when (and (listp vl) (eq (car vl) '&whole))
- (push (cadr vl) *vnames*)
- (setq whole (c1make-var (cadr vl) ss is ts))
- (push whole *dm-vars*)
- (push whole *vars*)
- (setq vl (cddr vl))
- )
- (let ((env-m (and (listp vl) (do ((tail vl (cdr tail)))
- ((not (consp tail)) nil)
- (when (eq '&environment (car tail))
- (return tail))))))
- (when env-m
- (push (cadr env-m) *vnames*)
- (setq env (c1make-var (cadr env-m) ss is ts))
- (push env *dm-vars*)
- (push env *vars*)
- (setq vl (append (ldiff vl env-m) (cddr env-m)))))
- (multiple-value-setq (vl ppn) (c1dm-vl vl ss is ts))
-
- (check-vdecl *vnames* ts is)
- (setq body (c1decl-body other-decls body))
- (add-info *dm-info* (cadr body))
- (cond ((eql setjmps *setjmps*))
- (t(setf (info-volatile *dm-info*) t)
- (setf (get macro-name 'contains-setjmp) t)
- ))
- (dolist* (v *dm-vars*) (check-vref v))
- (list doc ppn whole env vl body *dm-info*)
- )
-
- (defun c1dm-vl (vl ss is ts)
- (do ((optionalp nil) (restp nil) (keyp nil) (allow-other-keys-p nil)
- (auxp nil)
- (requireds nil) (optionals nil) (rest nil) (key-flag nil)
- (keywords nil) (auxs nil) (allow-other-keys nil)
- (n 0) (ppn nil)
- )
- ((not (consp vl))
- (when vl
- (when restp (dm-bad-key '&rest))
- (setq rest (c1dm-v vl ss is ts)))
- (values (list (reverse requireds) (reverse optionals) rest key-flag
- (reverse keywords) allow-other-keys (reverse auxs))
- ppn)
- )
- (let ((v (car vl)))
- (declare (object v))
- (cond
- ((eq v '&optional)
- (when optionalp (dm-bad-key '&optional))
- (setq optionalp t)
- (pop vl))
- ((or (eq v '&rest) (eq v '&body))
- (when restp (dm-bad-key v))
- (setq rest (c1dm-v (cadr vl) ss is ts))
- (setq restp t optionalp t)
- (setq vl (cddr vl))
- (when (eq v '&body) (setq ppn n)))
- ((eq v '&key)
- (when keyp (dm-bad-key '&key))
- (setq keyp t restp t optionalp t key-flag t)
- (pop vl))
- ((eq v '&allow-other-keys)
- (when (or (not keyp) allow-other-keys-p)
- (dm-bad-key '&allow-other-keys))
- (setq allow-other-keys-p t allow-other-keys t)
- (pop vl))
- ((eq v '&aux)
- (when auxp (dm-bad-key '&aux))
- (setq auxp t allow-other-keys-p t keyp t restp t optionalp t)
- (pop vl))
- (auxp
- (let (x init)
- (cond ((symbolp v) (setq x v init (c1nil)))
- (t (setq x (car v))
- (if (endp (cdr v))
- (setq init (c1nil))
- (setq init (c1expr* (cadr v) *dm-info*)))))
- (push (list (c1dm-v x ss is ts) init) auxs))
- (pop vl))
- (keyp
- (let (x k init (sv nil))
- (cond ((symbolp v)
- (setq x v k (intern (string v) 'keyword) init (c1nil)))
- (t (if (symbolp (car v))
- (setq x (car v)
- k (intern (string (car v)) 'keyword))
- (setq x (cadar v) k (caar v)))
- (cond ((endp (cdr v)) (setq init (c1nil)))
- (t (setq init (c1expr* (cadr v) *dm-info*))
- (unless (endp (cddr v))
- (setq sv (caddr v)))))))
- (push (list k (c1dm-v x ss is ts) init
- (if sv (c1dm-v sv ss is ts) nil))
- keywords)
- )
- (pop vl))
- (optionalp
- (let (x init (sv nil))
- (cond ((symbolp v) (setq x v init (c1nil)))
- (t (setq x (car v))
- (cond ((endp (cdr v))
- (setq init (c1nil)))
- (t (setq init (c1expr* (cadr v) *dm-info*))
- (unless (endp (cddr v))
- (setq sv (caddr v)))))))
- (push (list (c1dm-v x ss is ts) init
- (if sv (c1dm-v sv ss is ts) nil))
- optionals))
- (pop vl)
- (incf n)
- )
- (t (push (c1dm-v v ss is ts) requireds)
- (pop vl)
- (incf n))
- )))
- )
-
- (defun c1dm-v (v ss is ts)
- (cond ((symbolp v)
- (push v *vnames*)
- (setq v (c1make-var v ss is ts))
- (push v *vars*)
- (push v *dm-vars*)
- v)
- (t (c1dm-vl v ss is ts))))
-
- (defun c1dm-bad-key (key)
- (cmperr "Defmacro-lambda-list contains illegal use of ~s." key))
-
- (defun c2dm (whole env vl body
- &aux (cvar (next-cvar)))
- (when (or *safe-compile* *compiler-check-args*)
- (wt-nl "check_arg(2);"))
- (cond (whole (setf (var-ref whole) (vs-push)))
- (t (vs-push)))
- (cond (env (setf (var-ref env) (vs-push)))
- (t (vs-push)))
- (c2dm-reserve-vl vl)
- (wt-nl "vs_top=sup;")
- (when whole (c2bind whole))
- (when env (c2bind env))
- (wt-nl "{object V" cvar "=base[0]->c.c_cdr;")
- (c2dm-bind-vl vl cvar)
- (wt "}")
- (c2expr body)
- )
-
- (defun c2dm-reserve-vl (vl)
- (dolist** (var (car vl)) (c2dm-reserve-v var))
- (dolist** (opt (cadr vl))
- (c2dm-reserve-v (car opt))
- (when (caddr opt) (c2dm-reserve-v (caddr opt))))
- (when (caddr vl) (c2dm-reserve-v (caddr vl)))
- (dolist** (kwd (car (cddddr vl)))
- (c2dm-reserve-v (cadr kwd))
- (when (cadddr kwd) (c2dm-reserve-v (cadddr kwd))))
- (dolist** (aux (caddr (cddddr vl)))
- (c2dm-reserve-v (car aux)))
- )
-
- (defun c2dm-reserve-v (v)
- (if (consp v)
- (c2dm-reserve-vl v)
- (setf (var-ref v) (vs-push))))
-
- (defun c2dm-bind-vl (vl cvar
- &aux
- (requireds (car vl)) (optionals (cadr vl))
- (rest (caddr vl)) (key-flag (cadddr vl))
- (keywords (car (cddddr vl)))
- (allow-other-keys (cadr (cddddr vl)))
- (auxs (caddr (cddddr vl)))
- )
- (declare (object requireds optionals rest key-flag keywords allow-other-keys
- auxs))
- (do ((reqs requireds (cdr reqs)))
- ((endp reqs))
- (declare (object reqs))
- (when (or *safe-compile* *compiler-check-args*)
- (wt-nl "if(endp(V" cvar "))invalid_macro_call();"))
- (c2dm-bind-loc (car reqs) `(car ,cvar))
- (when (or (cdr reqs) optionals rest key-flag
- *safe-compile* *compiler-check-args*)
- (wt-nl "V" cvar "=V" cvar "->c.c_cdr;")))
- (do ((opts optionals (cdr opts)))
- ((endp opts))
- (declare (object opts))
- (let ((opt (car opts)))
- (declare (object opt))
- (wt-nl "if(endp(V" cvar ")){")
- (let ((*clink* *clink*)
- (*unwind-exit* *unwind-exit*)
- (*ccb-vs* *ccb-vs*))
- (c2dm-bind-init (car opt) (cadr opt))
- (when (caddr opt) (c2dm-bind-loc (caddr opt) nil))
- )
- (wt-nl "} else {")
- (c2dm-bind-loc (car opt) `(car ,cvar))
- (when (caddr opt) (c2dm-bind-loc (caddr opt) t)))
- (when (or (cdr opts) rest key-flag
- *safe-compile* *compiler-check-args*)
- (wt-nl "V" cvar "=V" cvar "->c.c_cdr;"))
- (wt "}"))
- (when rest (c2dm-bind-loc rest `(cvar ,cvar)))
- (dolist** (kwd keywords)
- (let ((cvar1 (next-cvar)))
- (wt-nl
- "{object V" cvar1 "=getf(V" cvar ",VV[" (add-symbol (car kwd))
- "],OBJNULL);")
- (wt-nl "if(V" cvar1 "==OBJNULL){")
- (let ((*clink* *clink*)
- (*unwind-exit* *unwind-exit*)
- (*ccb-vs* *ccb-vs*))
- (c2dm-bind-init (cadr kwd) (caddr kwd))
- (when (cadddr kwd) (c2dm-bind-loc (cadddr kwd) nil))
- (wt-nl "} else {"))
- (c2dm-bind-loc (cadr kwd) `(cvar ,cvar1))
- (when (cadddr kwd) (c2dm-bind-loc (cadddr kwd) t))
- (wt "}}")))
- (when (and (or *safe-compile* *compiler-check-args*)
- (null rest)
- (null key-flag))
- (wt-nl "if(!endp(V" cvar "))invalid_macro_call();"))
- (when (and (or *safe-compile* *compiler-check-args*)
- key-flag
- (not allow-other-keys))
- (wt-nl "check_other_key(V" cvar "," (length keywords))
- (dolist** (kwd keywords)
- (wt ",VV[" (add-symbol (car kwd)) "]"))
- (wt ");"))
- (dolist** (aux auxs)
- (c2dm-bind-init (car aux) (cadr aux)))
- )
-
- (defun c2dm-bind-loc (v loc)
- (if (consp v)
- (let ((cvar (next-cvar)))
- (wt-nl "{object V" cvar "= " loc ";")
- (c2dm-bind-vl v cvar)
- (wt "}"))
- (c2bind-loc v loc)))
-
- (defun c2dm-bind-init (v init)
- (if (consp v)
- (let* ((*vs* *vs*) (*inline-blocks* 0)
- (cvar (next-cvar))
- (loc (car (inline-args (list init) '(t)))))
- (wt-nl "{object V" cvar "= " loc ";")
- (c2dm-bind-vl v cvar)
- (wt "}")
- (close-inline-blocks))
- (c2bind-init v init)))
-
-
-
-